use std::{collections::{BTreeMap, BTreeSet}, path::Path};

use serde::{Deserialize, Deserializer};

use super::Opener;
use crate::config::{Pattern};


use crate::config::MERGED_SPARROW;
use crate::inspect;

#[derive(Debug)]
pub struct Open {
    openers : BTreeMap<String,Vec<Opener>> , 
    rules : Vec<OpenRule> , 
}


#[derive(Debug,Deserialize)] 
struct OpenRule{
    name : Option<Pattern> ,
    mime: Option<Pattern> , 
    #[serde(rename="use")] 
    use_ : String , 
}

impl Open {
    pub fn new() -> Self {
        /**
        查看Open结构体
        */ 
        let open = toml::from_str::<Open>(&MERGED_SPARROW).unwrap() ;
        // println!("{:?}" , &MERGED_SPARROW)  ; 
        // inspect!(open) ;
        // inspect!(open) ;
         toml::from_str::<Open>(&MERGED_SPARROW)
            .unwrap_or_else(|e| panic!("read \"Open\" from sparrow.toml failed with: {} " , e))
    }
    pub fn openers(&self, path: impl AsRef<Path>, mime: impl AsRef<str>) -> Option<Vec<&Opener>> {
        self.rules.iter().find_map(|rule| {
            if rule.name.as_ref().map_or(false, |e| e.match_path(&path, Some(false)))
                || rule.mime.as_ref().map_or(false, |m| m.matches(&mime))
            {
                self.openers.get(&rule.use_).map(|v| v.iter().collect())
            } else {
                None
            }
        })
    }
    
    
    // 找出多个目标文件或者目录共有的Opener实例  
    pub fn common_openers<'a>(
        &self,
        targets: &[(impl AsRef<Path>, impl AsRef<str>)],
    ) -> Vec<&Opener> {
        let grouped = targets.into_iter().filter_map(|(p, m)| self.openers(p, m)).collect::<Vec<_>>();
        let flat = grouped.iter().flatten().cloned().collect::<BTreeSet<_>>();
        flat.into_iter().filter(|o| grouped.iter().all(|g| g.contains(o))).collect()
    }
}



// 通过中间结构体实现跨表映射
impl<'de> Deserialize<'de> for Open {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {

        #[derive(Deserialize)]
        struct OuterOpen {
            rules: Vec<OpenRule>,
        }
        #[derive(Deserialize)]
        struct Outer {
            opener: BTreeMap<String, Vec<Opener>>,  //映射顶层[opener]表
            open:   OuterOpen, // 映射顶层[open]表
        }
        
        

        let outer = Outer::deserialize(deserializer)?;
        Ok(Self { openers: outer.opener, rules: outer.open.rules })
    }
}
